SVM: handle page faults in emulated instruction fetches
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 17 Mar 2008 11:39:50 +0000 (11:39 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 17 Mar 2008 11:39:50 +0000 (11:39 +0000)
Deal with failures in hvm_copy_from_guest_virt when fetching
instructions in the various SVM emulation paths.  Since we know that
the instruction was fetchable by the hardware, we can usually just
return from the VMEXIT and try again; whatever caused us to fail will
cause the hardware to fail next time and we'll get the correct exit
code.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
xen/arch/x86/hvm/svm/emulate.c
xen/arch/x86/hvm/svm/svm.c

index 530ed4606a66f2e715972f018cfd66952bc4a53c..cdf0059c993b6f45c9cfc63c7c235c10f8cd523d 100644 (file)
@@ -117,7 +117,9 @@ int __get_instruction_length_from_list(struct vcpu *v,
     }
     else
     {
-        inst_copy_from_guest(buffer, svm_rip2pointer(v), MAX_INST_LEN);
+        if ( inst_copy_from_guest(buffer, svm_rip2pointer(v), MAX_INST_LEN)
+             != MAX_INST_LEN )
+            return 0;
         buf = buffer;
     }
 
index ba934c1399aec84bda8ad7bd5c1eb856ee8de0c5..e29aeda008494501010971183af9a349b1c74dea 100644 (file)
@@ -943,6 +943,10 @@ static void svm_vmexit_do_cpuid(struct cpu_user_regs *regs)
 {
     unsigned int eax, ebx, ecx, edx, inst_len;
 
+    inst_len = __get_instruction_length(current, INSTR_CPUID, NULL);
+    if ( inst_len == 0 ) 
+        return;
+
     eax = regs->eax;
     ebx = regs->ebx;
     ecx = regs->ecx;
@@ -955,7 +959,6 @@ static void svm_vmexit_do_cpuid(struct cpu_user_regs *regs)
     regs->ecx = ecx;
     regs->edx = edx;
 
-    inst_len = __get_instruction_length(current, INSTR_CPUID, NULL);
     __update_guest_eip(regs, inst_len);
 }
 
@@ -1166,6 +1169,8 @@ static void svm_vmexit_do_hlt(struct vmcb_struct *vmcb,
     unsigned int inst_len;
 
     inst_len = __get_instruction_length(curr, INSTR_HLT, NULL);
+    if ( inst_len == 0 )
+        return 0;
     __update_guest_eip(regs, inst_len);
 
     /* Check for pending exception or new interrupt. */
@@ -1354,6 +1359,8 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
 
     case VMEXIT_VMMCALL:
         inst_len = __get_instruction_length(v, INSTR_VMCALL, NULL);
+        if ( inst_len == 0 )
+            break;
         HVMTRACE_1D(VMMCALL, v, regs->eax);
         rc = hvm_do_hypercall(regs);
         if ( rc != HVM_HCALL_preempted )